﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;

namespace memcached
{
    /// <summary>
    /// Various helper methods.
    /// </summary>
    public static class Utils
    {
        #region Function caching
        /// <summary>
        /// Try to get item from cache, if failed call generator and cache result value it not null.
        /// </summary>
        /// <typeparam name="T">type of item value</typeparam>
        /// <param name="cache">not null</param>
        /// <param name="key">not null</param>
        /// <param name="generator">not null</param>
        /// <returns>null only if generator returned null</returns>
        public static T CacheResult<T>(ICache cache, string key, Func<T> generator)
        {
            if (key == null)
                throw new ArgumentNullException("key");
            if (cache == null)
                throw new ArgumentNullException("cache");
            bool success;
            object res = cache.Get(key, out success);
            if (!success || res == null || !(res is T))
            {
                res = generator();
                if (res != null)
                {
                    cache.Set(key, res);
                }
            }
            return (T)res;
        }
        #endregion

        #region Compression
        /// <summary>
        /// Compress.
        /// </summary>
        /// <param name="bytes">not null</param>
        /// <returns>not null</returns>
        public static byte[] Compress(byte[] bytes)
        {
            using (MemoryStream ms = new MemoryStream(bytes.Length))
            {
                using (DeflateStream gz = new DeflateStream(ms, CompressionMode.Compress, false))
                {
                    gz.Write(bytes, 0, bytes.Length);
                }
                ms.Close();
                return ms.ToArray();
            }
        }

        /// <summary>
        /// Decompress.
        /// </summary>
        /// <param name="bytes">not null</param>
        /// <returns>null if failed</returns>
        public static byte[] Decompress(byte[] bytes)
        {
            using (MemoryStream ms = new MemoryStream(bytes, false))
                try
                {
                    using (DeflateStream gzs = new DeflateStream(ms, CompressionMode.Decompress, false))
                    {
                        using (MemoryStream dest = new MemoryStream(bytes.Length * 2))
                        {
                            byte[] tmp = new byte[bytes.Length];
                            int read;
                            while ((read = gzs.Read(tmp, 0, tmp.Length)) != 0)
                            {
                                dest.Write(tmp, 0, read);
                            }
                            dest.Close();
                            return dest.ToArray();
                        }
                    }
                }
                catch (InvalidDataException)
                {
                    return null;
                }
        }

        /// <summary>
        /// </summary>
        public static byte[] Compress(string s)
        {
            return Compress(UTF8Encoding.UTF8.GetBytes(s));
        }

        /// <summary>
        /// </summary>
        public static string DecompressString(byte[] bytes)
        {
            byte[] s = Decompress(bytes);
            return s != null ? UTF8Encoding.UTF8.GetString(s) : null;
        }
        #endregion
    }
}